/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit.features.mocking;

import picounit.features.base.StubFactory;
import picounit.features.registry.ClassUtil;
import picounit.mocker.MockFactory;

import java.lang.reflect.Array;
import java.lang.reflect.Modifier;

public class TypeFactory {
	private final StubFactory stubFactory;
	private final MockFactory mockFactory;
	private final ClassUtil classUtil;

	public TypeFactory(StubFactory stubFactory, MockFactory mockFactory, ClassUtil classUtil) {
		this.stubFactory = stubFactory;
		this.mockFactory = mockFactory;
		this.classUtil = classUtil;
	}

	public <T> boolean isNotCastable(Class<T> type) {
		return isVoid(type) || isPrimative(type) || isArray(type);
	}

	@SuppressWarnings("unchecked")
	public <T> T createNotCastable(Class<T> type) {
		if (isVoid(type)) {
			return null;
		}
		else if (isPrimative(type)) {
			return stubFactory.create(type);
		}

		return (T) Array.newInstance(type.getComponentType(), 0);
	}

	public <T> T create(Class<T> type) {
		return classUtil.isSimple(type) || isFinal(type)
			? stubFactory.create(type)
			: mockFactory.mock(type);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// Implementation methods
	///////////////////////////////////////////////////////////////////////////////////////////////

	private boolean isPrimative(Class type) {
		return classUtil.isPrimative(type);
	}

	private boolean isVoid(Class type) {
		return type.equals(void.class);
	}
	
	private boolean isArray(Class type) {
		return type.isArray();
	}

	private boolean isFinal(Class type) {
		return Modifier.isFinal(type.getModifiers());
	}
}